//board.cpp

#include "board.h"
#include <stdio.h>
#include "smiley.xpm"
#include "gaucho.xpm"
#include "storke.xpm"
#include <wx/aboutdlg.h>


//This is the object's constructor, which initializes all of its member variables and sets up all the event handlers.
board::board(wxFrame *parent)
  : wxPanel(parent, wxID_ANY, wxDefaultPosition,
	    wxDefaultSize, wxBORDER_NONE)
{
  turnongaucho = false;
  timer = new wxTimer(this, 1);
  
  m_stsbar = parent->GetStatusBar();
  m_stsbar->SetFieldsCount(2);

  isStarted = false;
  isPaused = false;

  beer = new resources();

  Connect(wxEVT_TIMER, wxCommandEventHandler(board::OnTimer));
  Connect(wxEVT_LEFT_UP, wxMouseEventHandler(board::OnLeftClick));
   
  //initialize bigcounter
  bigcounter = 0;
  
  //initialize our storkeTower object
  st = new storkeTower();
  
  pair p;
  p.x = 20;
  p.y = 10;
  st->setLoc(p);

  //initialize array of enemy pointers/enemies
  for (int k=0;k<enemyarraysize;k++)
    {
      if(k==0)
	enemyarray[k]= new enemyd1();
      else if(k==1)
	enemyarray[k]= new enemyd2();
      else if(k==2)
	enemyarray[k]= new enemyd3();
      else if(k==3)
	enemyarray[k]= new enemyd4();
      else if(k==4)
	enemyarray[k]= new enemyd5();
      else if(k==5)
	enemyarray[k]= new enemyd6();
      else if(k==6)
	enemyarray[k]= new enemyd7();
      else if(k==7)
	enemyarray[k]= new enemyd8();
      else if(k==8)
	enemyarray[k]= new enemyd9();
      else if(k==9)
	enemyarray[k]= new enemyd10();
      else
	enemyarray[k] = new enemy();
    }

  //initialize array of gaucho pointers to NULL
  for (int h=0;h<gauchoarraysize;h++)
    gauchoarray[h] = NULL;
    
  for(int i=0;i<21;i++)
    {
      for (int j=0;j<21;j++)
	{
	  //initializing the 5 enemy's coordinates to (0,0),(0,1),(0,2),(0,3),(0,4),(0,5)....(0,20) respectively
	   
	  fakeboard[i][j].point.x = i;
	  fakeboard[i][j].point.y = j;

	  if(i==0)
	    {
	      if(j<enemyarraysize)
		{
		  enemyarray[j]->setCoordinates(i,j);

		  fakeboard[i][j].full = true;
		  fakeboard[i][j].type = 0;
		}
	    }
	  else
	    {
	      fakeboard[i][j].full = false;
	      fakeboard[i][j].type =2;
	    }
	}      
    }

  //we now place storkeTower object on our 'fakeboard'
  fakeboard[p.x][p.y].full = true;
    

  //fakeboard looks like
  //(0,0) (1,0) (2,0) (3,0) (4,0) (5,0) (6,0)....(20,0)
  //(0,1) (1,1) (2,1) (3,1) (4,1) ...
  //(0,2) (1,2) (2,2) ...
  //.
  //..
  //(0,20)

  //where enemyarray is initialized to hold the pairs in the 0 column

}

// This function allows for the placement of gauchos.
void board::setTurnongaucho(bool x)
{
  this->turnongaucho = x;
}

//This function determines where an enemy will move next based on its current position on the board.
void board::Invade()
{

  //this function makes the enemies snake accross the board one time
  int snake = 4;

  for (int i=(enemyarraysize -1);i>-1;i--)
    {
      if(enemyarray[i] !=NULL)
	{
	  if(enemyarray[i]->getCoordinates().x%snake ==0) //if we are in even column
	    {
	  	 
	      if(enemyarray[i]->getCoordinates().y == 20)
		{
		  bigcounter++;
		  //set position on board that enemy is currently at to false

		  fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = false;
		  fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].type = 2;
		 
		  //next we move the enemy over, so we update its x-coordinate
		  //and update fakeboard accordingly
		  
		  enemyarray[i]->setX( enemyarray[i]->getCoordinates().x + 1);
		  fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = true;	  
		  fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].type = 1;	  
		
		}
	      else{
	   
		fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = false;
		fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].type = 2;
		enemyarray[i]->setY(enemyarray[i]->getCoordinates().y + 1);
		fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = true;
		fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].type = 1;	   
	      }

	    }
	  
	  else if(enemyarray[i]->getCoordinates().x%snake == 2)
	    {

	      if(enemyarray[i]->getCoordinates().y == 0)
		{
	      
		  fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = false;
		  //next we move the enemy over, so we update its x-coordinate
		  fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].type = 2;
		  enemyarray[i]->setX(enemyarray[i]->getCoordinates().x + 1);
	      
	      
		  fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = true;	  
		  fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].type = 1;	   
		}
	      else{

		fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = false;
		fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].type = 2;
		enemyarray[i]->setY(enemyarray[i]->getCoordinates().y - 1);
		fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = true;
		fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].type = 1;	
	      }
	  
	  
	    }
	  else{

	    fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = false;
	    fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].type = 2;
	    enemyarray[i]->setX(enemyarray[i]->getCoordinates().x + 1);
	    fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = true;
	    fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].type = 1;	
	    
	  }
   
	  if(checkPosition(enemyarray[i])==true)
	    {
	      fakeboard[enemyarray[i]->getCoordinates().x][enemyarray[i]->getCoordinates().y].full = false;
	      delete enemyarray[i];
	      enemyarray[i]=NULL;
	     
	    }
	}
    }


}

//This function sets the isStarted variable to true and starts our timer.
void board::Start()
{
  Connect(wxEVT_PAINT, wxPaintEventHandler(board::OnPaint));
  if (isPaused)
    return;

  if(st->getLives() > 0)
    {
      isStarted = true;
      timer->Start(100); //1000
    }
}

//This function stops the timer and redraws the board.
void board::Pause()
{
  if (!isStarted)
    return;

  isPaused = !isPaused;
  if (isPaused) {
    timer->Stop();
    m_stsbar->SetStatusText(wxT("paused, press 'pause' again to continue"));
  } else {
    showResources();
    if(st->getLives() > 0)
      timer->Start(100);
  }
  Refresh();
}

//This function is called every time the timer goes off, and it calls DrawSquare to draw all the objects currently initialized on the board.
void board::OnPaint(wxPaintEvent& event)
{
  
  //we call this function 6 times, which then draws 6 individual squares.
  wxPaintDC dc(this);
  // The wxIcons are functions to create wxIcons from xpm image files to display.
  wxIcon icon(smiley_xpm);
  wxIcon icon2(gaucho_xpm);
  wxIcon icon3(storke_xpm);




  //Colors in all the pixels on the board using squares
  for(int f = 0; f< 22; f++)
    {
      for(int g = 0; g<22;g++)
	{
	  DrawSquare(dc, 37*fakeboard[f][g].point.x, 37*fakeboard[f][g].point.y,2);
	
	}

    }

  //for drawing our st object
  //
  // DrawSquare(dc, 37*st->getLoc().x, 37*st->getLoc().y, 1); //Storke Tower as a Square
  dc.DrawIcon(icon3,37*st->getLoc().x, 37*st->getLoc().y);    //Storke Tower as an image of storke tower

  //for drawing our gauchos (the number of gauchos are specified by gauchoarraysize)
  for (int i=0;i < gauchoarraysize;i++)  
    if(gauchoarray[i]!=NULL)
      {
	//These if-statements make sure that our gaucho stays on the board
	if(gauchoarray[i]->getLoc().x > 20)
	  gauchoarray[i]->setX(20);
	if(gauchoarray[i]->getLoc().y > 20)
	  gauchoarray[i]->setY(20);
	//DrawSquare(dc, (gauchoarray[i]->getLoc().x * 37), (gauchoarray[i]->getLoc().y*37), 3); //Gauchos as Squares
	//put gauchos on fakeboard
	dc.DrawIcon(icon2,(gauchoarray[i]->getLoc().x * 37), (gauchoarray[i]->getLoc().y*37)); //Gauchos as images
       
	//	fakeboard[gauchoarray[i]->getLoc().x][gauchoarray[i]->getLoc().y].full= true;
      }

  //for drawing our enemies, that may or may not have been shot down by the gaucho
  for (int j=0; j<enemyarraysize; j++)
    {

      if(enemyarray[j] != NULL){
	//if the gauchos have been placed, we now have the ability to shoot enemies
	for (int k=0;k<gauchoarraysize;k++)
	  {
	    dc.DrawIcon(icon, (37*enemyarray[j]->getCoordinates().x),(37*enemyarray[j]->getCoordinates().y)); //Enemies displayed as an image
	    //DrawSquare(dc,(37*enemyarray[j]->getCoordinates().x),(37*enemyarray[j]->getCoordinates().y),1); //Enemies displayed as a square
	  }
	
      } 
    }
}

//This function is called every time the timer goes off and it calls Invade() to move all the current enemies on the board to a new location and then calls Refresh() to redraw them in their new location.
void board::OnTimer(wxCommandEvent& event)
{
  wxPaintDC dc(this);
  Invade();
  Kill();
  showStLives();
  showResources();
  Refresh();

  int count=0;

  for(int i=0; i<enemyarraysize; i++)
    {
      if(enemyarray[i] != NULL)
	count++;
    }
  if(count == 0 && st->getLives() > 0)
    {
      timer->Stop();

      wxAboutDialogInfo win;
      win.SetName(_("Winner"));
      win.SetDescription(_("You won!! =D Congratulations!"));

      wxAboutBox(win);
    }
}

//This function is called every time the user clicks on the board. It then initializes a new gaucho object and places it at the location the user clicked on.
void board::OnLeftClick(wxMouseEvent& event)
{
  //the 'turnongaucho' bool var makes sure that when the user clicks on the board before the game starts,
  //it does not affect the game whatsoever

  if(turnongaucho == true){
    
    static int i=0;
    int clickX;
    int clickY;
    pair k;

    clickX = event.GetX();
    clickY = event.GetY();

    //we try to match gaucho's coordinates with coordinates of fakeboard
    k.x = clickX/37;
    k.y = clickY/37;

    if (i < gauchoarraysize) 
      {

	//make sure the fakeboard is keeping track of gaucho placement
	if(fakeboard[k.x][k.y].full==false)
	  {
	    if(i == 0 && beer->getCounter() >= 1)
	      {
		gauchoarray[i] = new gaucho();

		beer->decrement(1);

		fakeboard[k.x][k.y].full = true;
	    
		gauchoarray[i]->setLoc(k);

		//increment i to say that new gaucho has been placed
		i++;
	      }
	    else if(i == 1 && beer->getCounter() >= 5)
	      {
		gauchoarray[i] = new gauchod1();

		beer->decrement(5);

		fakeboard[k.x][k.y].full = true;
	    
		gauchoarray[i]->setLoc(k);

		//increment i to say that new gaucho has been placed
		i++;
	      }
	    else if(i == 2 && beer->getCounter() >= 10)
	      {
		gauchoarray[i] = new gauchod2();

		beer->decrement(10);

		fakeboard[k.x][k.y].full = true;
	    
		gauchoarray[i]->setLoc(k);

		//increment i to say that new gaucho has been placed
		i++;
	      }
	    else if(i == 3 && beer->getCounter() >= 15)
	      {
		gauchoarray[i] = new gauchod3();

		beer->decrement(15);

		fakeboard[k.x][k.y].full = true;
	    
		gauchoarray[i]->setLoc(k);

		//increment i to say that new gaucho has been placed
		i++;
	      }
	  }
      }
  }
}


//This function draws a square on the board at location x,y with a specific color.
void board::DrawSquare(wxPaintDC& dc, int x, int y,int color)
{
  
  static wxColour colors[] = { wxColour(0, 0, 0), wxColour(204, 102, 102), 
			       wxColour(102, 204, 102), wxColour(102, 102, 204), 
			       wxColour(204, 204, 102), wxColour(204, 102, 204), 
			       wxColour(102, 204, 204), wxColour(218, 170, 0) };

  static wxColour light[] = { wxColour(0, 0, 0), wxColour(248, 159, 171),
			      wxColour(121, 252, 121), wxColour(121, 121, 252), 
			      wxColour(252, 252, 121), wxColour(252, 121, 252), 
			      wxColour(121, 252, 252), wxColour(252, 198, 0) };

  static wxColour dark[] = { wxColour(0, 0, 0), wxColour(128, 59, 59), 
			     wxColour(59, 128, 59), wxColour(59, 59, 128), 
			     wxColour(128, 128, 59), wxColour(128, 59, 128), 
			     wxColour(59, 128, 128), wxColour(128, 98, 0) };


  wxPen pen(light[3]); 
  pen.SetCap(wxCAP_PROJECTING);
  dc.SetPen(pen);

  dc.DrawLine(x, y + SquareHeight() - 1, x, y);
  dc.DrawLine(x, y, x + SquareWidth() - 1, y);

  wxPen darkpen(dark[5]);
  darkpen.SetCap(wxCAP_PROJECTING);
  dc.SetPen(darkpen);

  dc.DrawLine(x + 1, y + SquareHeight() - 1,
	      x + SquareWidth() - 1, y + SquareHeight() - 1);
  dc.DrawLine(x + SquareWidth() - 1, 
	      y + SquareHeight() - 1, x + SquareWidth() - 1, y + 1);

  dc.SetPen(*wxTRANSPARENT_PEN);
  dc.SetBrush(wxBrush(colors[color])); 
  dc.DrawRectangle(x + 1, y + 1, SquareWidth() - 2, 
		   SquareHeight() - 2);
}

//This function checks to see if an enemy object is in the same position as the storkeTower object. If it is, it return true. Else it returns false.
bool board::checkPosition(enemy* badguy)
{
  if (st->getLoc().x == badguy->getCoordinates().x && st->getLoc().y == badguy->getCoordinates().y)
    {
      st->decrementLives();
      if(st->getLives() <= 0)
	{
	  timer->Stop();

	  wxAboutDialogInfo lose;
	  lose.SetName(_("Loser"));
	  lose.SetDescription(_("You lost ='( Nice try, maybe next time!"));

	  wxAboutBox(lose);
	}
      return true;
    }
  return false;
}


bool board::canShoot(enemy* badguy, gaucho* goodguy) //we pass a specific gaucho's location
{
  if (goodguy->check_range(badguy) == true)
    return true;
  else
    return false;

}

void board::Kill()
{
  //'killpause' along with 'death' manipulates the amount of enemies that should die when they are in range of the gaucho
 

  static int killpause=1;
  int death = 2;

  for (int i=0;i<gauchoarraysize;i++)
    {
      for (int j=0;j<enemyarraysize;j++)
	{
	  if(killpause%death == 0 && enemyarray[j]!=NULL && gauchoarray[i]!=NULL)
	    {
	      if(canShoot(enemyarray[j], gauchoarray[i])){
		enemyarray[j]->setHealthPoints(enemyarray[j]->getHealthPoints() - gauchoarray[i]->getDamage());
		if (enemyarray[j]->getHealthPoints() <= 0)
		  {
		    fakeboard[enemyarray[j]->getCoordinates().x][enemyarray[j]->getCoordinates().y].full = false;
		    delete enemyarray[j];
		    enemyarray[j]=NULL;
		  }
		break;
	      }
	    }
	}
    }

  killpause++;

}

// This function shows the amount of lives storke tower has at the beginning of the game.
void board::showStLives()
{
  wxString mynewstring = wxString::Format(_T("lives: %d"), st->getLives());
  m_stsbar->SetStatusText(mynewstring,1);
}
// This functions shows the amount of resources the player has at any given point in the game.
void board::showResources()
{
  static int control = 0;

  if(control%5 == 0)
    beer->increment();
  wxString mynewstring = wxString::Format(_T("resources: %d"), beer->getCounter());
  m_stsbar->SetStatusText(mynewstring,0);
  control++;
}
